home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fsconsist / fsconsistCache.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  77KB  |  2,329 lines

  1. /* 
  2.  * fsCacheConsist.c --
  3.  *
  4.  *    Routines used to keep the file system caches consistent.  The
  5.  *    server maintains a list of client machines that have the file
  6.  *    open.  This list indicates how many opens per client, if the file
  7.  *    is being cached, and if the file is open for writing on a client.
  8.  *    The client list is updated when files are opened, closed, and removed.
  9.  *
  10.  *    SYNCHRONIZATION:  There are two classes of procedures here: those
  11.  *    that make call-backs to clients, and those that just examine the
  12.  *    client list.  All access to a client list is synchronized using
  13.  *    a monitor lock embedded in the consist structure.  Furthermore,
  14.  *    consistency actions are serialized by setting a flag during
  15.  *    call-backs (CONSIST_IN_PROGRESS).  There is a possible deadlock
  16.  *    if the monitor lock is held during a call-back because this
  17.  *    prevents a close operation from completing. (At close time the
  18.  *    client list is adjusted but no call-backs are made.  Also, the client
  19.  *    has its handle locked which blocks our call-back.)  Accordingly,
  20.  *    both the handle lock and the monitor lock are released during
  21.  *    a call-back.  The CONSIST_IN_PROGRESS flag is left on to prevent
  22.  *    other consistency actions during the call-back.
  23.  *
  24.  * Copyright 1986 Regents of the University of California.
  25.  * All rights reserved.
  26.  */
  27.  
  28. #ifndef lint
  29. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fsconsist/fsconsistCache.c,v 9.32 92/08/10 17:23:58 mgbaker Exp $ SPRITE (Berkeley)";
  30. #endif
  31.  
  32. #include    <sprite.h>
  33. #include    <fs.h>
  34. #include    <fsutil.h>
  35. #include    <fsconsist.h>
  36. #include    <fscache.h>
  37. #include    <fsStat.h>
  38. #include    <fslcl.h>
  39. #include    <fsprefix.h>
  40. #include    <hash.h>
  41. #include    <vm.h>
  42. #include    <proc.h>
  43. #include    <sys.h>
  44. #include    <rpc.h>
  45. #include    <recov.h>
  46. #include    <timer.h>
  47. #include    <dbg.h>
  48. #include     <fsio.h>
  49. #include    <fsrmt.h>
  50. #include    <fsdm.h>
  51.  
  52. #include <stdio.h>
  53.  
  54. #include    <fsrecov.h>
  55.  
  56. #define    LOCKPTR    (&consistPtr->lock)
  57.  
  58. Boolean    fsconsist_Debug = FALSE;
  59. Boolean    fsconsist_ClientCachingEnabled = TRUE;
  60.  
  61. /*
  62.  * Flags for the Fsconsist_Info struct that's defined in fsInt.h
  63.  *
  64.  *    FS_CONSIST_IN_PROGRESS    Cache consistency is being performed on this
  65.  *                file.
  66.  *    FS_CONSIST_ERROR    There was an error during the cache 
  67.  *                consistency.
  68.  *    FS_CONSIST_TIMEOUT    There is a timeout setup for the consistency
  69.  *                actions.
  70.  */
  71. #define    FS_CONSIST_IN_PROGRESS    0x1
  72. #define    FS_CONSIST_ERROR    0x2
  73. #define FS_CONSIST_TIMEOUT    0x4
  74.  
  75. /*
  76.  * Clients have an (arbitrary) number of minutes to complete call-back
  77.  * actions before the server blows them off and lets an open operation
  78.  * complete.  This time has to be enough to let a client with a large
  79.  * main-memory cache writeback a large file.
  80.  */
  81. int fsconsist_TimeoutMinutes = 1;
  82.  
  83. /*
  84.  * Rpc to send when forcing a client to invalidate or write back a file.
  85.  */
  86.  
  87. typedef struct ConsistMsg {
  88.     Fs_FileID    fileID;        /* Which file to invalidate. */
  89.     int        flags;        /* One of the flags defined below. */
  90.     int        openTimeStamp;    /* Open that this rpc pertains to. */
  91.     int        version;    /* Version number of the file */
  92. } ConsistMsg;
  93.  
  94. /*
  95.  * Message sent when the client has completed the work requested by the server.
  96.  * This is actually the request part of the rpc transaction.
  97.  */
  98.  
  99. typedef struct ConsistReply {
  100.     Fs_FileID         fileID;
  101.     Fscache_Attributes    cachedAttr;
  102.     ReturnStatus    status;
  103. } ConsistReply;
  104.  
  105.  
  106. /*
  107.  * Structure used to keep track of outstanding cache consistency requests.
  108.  */
  109. typedef struct {
  110.     List_Links    links;
  111.     int        clientID;
  112.     int        flags;
  113. } ConsistMsgInfo;
  114.  
  115. /*
  116.  * Global time stamp.  A time stamp is returned to clients on each open
  117.  * and on cache consistency messages.  This way clients can detect races
  118.  * between open replies and consistency actions.
  119.  */
  120. static    int    openTimeStamp = 0;
  121.  
  122. /*
  123.  * Forward declarations.
  124.  */
  125. extern void StartConsistency _ARGS_((Fsconsist_Info *consistPtr, 
  126.             int clientID, int useFlags, Boolean *cacheablePtr));
  127. extern void UpdateList _ARGS_((Fsconsist_Info *consistPtr, int clientID, 
  128.         int useFlags, Boolean cacheable, int *openTimeStampPtr));
  129. extern ReturnStatus EndConsistency _ARGS_((Fsconsist_Info *consistPtr));
  130. extern void ConsistTimeoutIntr _ARGS_((Timer_Ticks time, ClientData data));
  131. extern void ConsistTimeout _ARGS_((ClientData data, 
  132.         Proc_CallInfo *callInfoPtr));
  133.  
  134. extern void ClientCommand _ARGS_((Fsconsist_Info *consistPtr,
  135.         Fsconsist_ClientInfo *clientPtr, int flags));
  136.  
  137. extern void ProcessConsist _ARGS_((ClientData data,Proc_CallInfo *callInfoPtr));
  138. extern void ProcessConsistReply _ARGS_((Fsconsist_Info *consistPtr, 
  139.         int clientID, ConsistReply *replyPtr));
  140.  
  141. extern char *ConsistType _ARGS_((int flags));
  142.  
  143.  
  144. /*
  145.  * ----------------------------------------------------------------------------
  146.  *
  147.  * Fsconsist_Init --
  148.  *
  149.  *      Initialize the client use information for a file.  This is done
  150.  *    before adding any clients so it just resets all the fields.
  151.  *
  152.  * Results:
  153.  *    None.
  154.  *
  155.  * Side effects:
  156.  *    Reset the client use state..
  157.  *
  158.  * ----------------------------------------------------------------------------
  159.  *
  160.  */
  161. void
  162. Fsconsist_Init(consistPtr, hdrPtr)
  163.     register Fsconsist_Info *consistPtr;    /* State to initialize */
  164.     Fs_HandleHeader *hdrPtr;            /* Back pointer to handle */
  165. {
  166.     Sync_LockInitDynamic(&consistPtr->lock, "Fs:consistLock");
  167.     consistPtr->flags = 0;
  168.     consistPtr->lastWriter = -1;
  169.     consistPtr->openTimeStamp = 0;
  170.     consistPtr->hdrPtr = hdrPtr;
  171.     List_Init(&consistPtr->clientList);
  172.     List_Init(&consistPtr->msgList);
  173.     consistPtr->consistDone.waiting = 0;
  174.     consistPtr->repliesIn.waiting = 0;
  175. }
  176.  
  177. /*
  178.  * ----------------------------------------------------------------------------
  179.  *
  180.  * Fsconsist_SyncLockCleanup --
  181.  *
  182.  *      Clean up Sync_Lock tracing for the cache lock.
  183.  *
  184.  * Results:
  185.  *    None.
  186.  *
  187.  * Side effects:
  188.  *    As above.
  189.  *
  190.  * ----------------------------------------------------------------------------
  191.  *
  192.  */
  193. /*ARGSUSED*/
  194. void
  195. Fsconsist_SyncLockCleanup(consistPtr)
  196.     Fsconsist_Info *consistPtr;    /* State to initialize */
  197. {
  198.     Sync_LockClear(&consistPtr->lock);
  199. }
  200.  
  201. /*
  202.  * ----------------------------------------------------------------------------
  203.  *
  204.  * Fsconsist_MappedConsistency --
  205.  *
  206.  *    Take action to ensure that everything is consistent for a
  207.  *    file that is being mapped.
  208.  *
  209.  * Results:
  210.  *    SUCCESS or FS_FILE_BUSY.
  211.  *
  212.  * Side effects:
  213.  *    Issues cache consistency messages.
  214.  *
  215.  * ----------------------------------------------------------------------------
  216.  *
  217.  */
  218. /*ARGSUSED*/
  219. ENTRY ReturnStatus
  220. Fsconsist_MappedConsistency(handlePtr, clientID, isMapped)
  221.     Fsio_FileIOHandle     *handlePtr;    /* File to check consistency of. */
  222.     int         clientID;    /* ID of the host doing the map. */
  223.     int            isMapped;    /* 1 if file is being mapped. */
  224. {
  225. #ifdef notdef
  226.     int                    cacheable;    /* Dummy. */
  227.     register Fsconsist_ClientInfo    *clientPtr;
  228.     register Fsconsist_Info        *consistPtr = &handlePtr->consist;
  229.     ReturnStatus            status;
  230.  
  231.     printf("Fsconsist_MappedConsistency: updating consistency (a)\n");
  232.     LOCK_MONITOR;
  233.  
  234.     printf("Fsconsist_MappedConsistency: updating consistency (b)\n");
  235.     StartConsistency(consistPtr, clientID, (int)(isMapped ? FS_MAP : 0),
  236.         &cacheable);
  237.  
  238.     printf("Fsconsist_MappedConsistency: updating consistency (c)\n");
  239.     LIST_FORALL(&consistPtr->clientList, (List_Links *)clientPtr) {
  240.     if (clientPtr->clientID == clientID) {
  241.         clientPtr->mapped = isMapped ? TRUE : FALSE;
  242.     }
  243.     }
  244.  
  245.     printf("Fsconsist_MappedConsistency: updating consistency (d)\n");
  246.     status = EndConsistency(consistPtr);
  247.     printf("Fsconsist_MappedConsistency: updating consistency (e)\n");
  248.  
  249.     UNLOCK_MONITOR;
  250.     return(status);
  251. #endif
  252.     return SUCCESS;
  253. }
  254.  
  255. /*
  256.  * ----------------------------------------------------------------------------
  257.  *
  258.  * Fsconsist_FileConsistency --
  259.  *
  260.  *    Take action to ensure that the caches are consistent for this
  261.  *    file.  This checks against use conflicts and will return an
  262.  *    non-SUCCESS status if the open should fail.  Otherwise this
  263.  *    makes call-backs to other clients to keep caches consistent.
  264.  *
  265.  * Results:
  266.  *    SUCCESS or FS_FILE_BUSY.  Also, *cacheablePtr set to TRUE if the
  267.  *    file is cacheable on the client.  *openTimeStampPtr is set to the
  268.  *    next open time stamp on the file.  Clients use this timeStamp
  269.  *    to catch races between open replies, which have the next timeStamp,
  270.  *    and consistency messages from other opens happening
  271.  *    at about the same time, which have the current timeStamp.
  272.  *
  273.  * Side effects:
  274.  *    Issues cache consistency messages and adds the client to the
  275.  *    list of clients of the file.
  276.  *    The handle is unlocked before Fsconsist_FileConsistency is called.
  277.  *
  278.  * ----------------------------------------------------------------------------
  279.  *
  280.  */
  281. ENTRY ReturnStatus
  282. Fsconsist_FileConsistency(handlePtr, clientID, useFlags, cacheablePtr,
  283.     openTimeStampPtr)
  284.     Fsio_FileIOHandle *handlePtr;    /* File to check consistency of. */
  285.     int         clientID;    /* ID of the host doing the open */
  286.     register int     useFlags;    /* useFlags from the open call */
  287.     Boolean        *cacheablePtr;    /* TRUE if file is cacheable. */
  288.     int            *openTimeStampPtr;/* Timestamp of open.  Used by clients
  289.                      * to catch races between open replies
  290.                      * and cache consistency messages */
  291. {
  292.     register Fsconsist_Info *consistPtr = &handlePtr->consist;
  293.     ReturnStatus status;
  294.  
  295.     LOCK_MONITOR;
  296.  
  297.     /*
  298.      * Go through the list of other clients using the file checking
  299.      * for conflicts and issuing cache consistency messages.
  300.      */
  301.     StartConsistency(consistPtr, clientID, useFlags, cacheablePtr);
  302.     /*
  303.      * Add ourselves to the list of clients using the file.
  304.      */
  305.     UpdateList(consistPtr, clientID, useFlags, *cacheablePtr,
  306.         openTimeStampPtr);
  307.     /*
  308.      * Now that we are all set up, and have told all the other clients
  309.      * using the file what they have to do, we wait for them to finish.
  310.      */
  311.     status = EndConsistency(consistPtr);
  312.     UNLOCK_MONITOR;
  313.     return(status);
  314. }
  315.  
  316. /*
  317.  * ----------------------------------------------------------------------------
  318.  *
  319.  * StartConsistency --
  320.  *
  321.  *      Initiate cache consistency action on a file.  This decides if the
  322.  *    client can cache the file, and then makes call-backs to other
  323.  *    clients so that caches stay consistent.  EndConsistency
  324.  *    should be called later to wait for the client replies.
  325.  *
  326.  * Results:
  327.  *    *cacheablePtr set to TRUE if the file is cacheable.   *fileBusyPtr
  328.  *    is set to FS_FILE_BUSY if the file is either being opened for execution
  329.  *    and it is already open for writing or vice versa.
  330.  *
  331.  * Side effects:
  332.  *    Sets the FS_CONSIST_IN_PROGRESS flag and makes call-backs to
  333.  *    clients.  The flag is cleared if the call-backs can't be made.
  334.  *
  335.  * ----------------------------------------------------------------------------
  336.  *
  337.  */
  338.  
  339. INTERNAL void
  340. StartConsistency(consistPtr, clientID, useFlags, cacheablePtr)
  341.     Fsconsist_Info    *consistPtr;    /* File's consistency state. */
  342.     int            clientID;    /* ID of host opening the file */
  343.     int            useFlags;    /* Indicates how they are using it */
  344.     Boolean        *cacheablePtr;    /* Return, TRUE if client can cache */
  345. {
  346.     register Fsconsist_ClientInfo *clientPtr;
  347.     register Fsconsist_ClientInfo *nextClientPtr;
  348.     register Fs_ConsistStats *statPtr = &fs_Stats.consist;
  349.     register Fs_MigStats *migStatPtr = &fs_Stats.mig;
  350.     register int openForWriting = useFlags & FS_WRITE;
  351.     register Boolean cacheable;
  352.     Boolean countMigration;    /* Set if we're supposed to increment a
  353.                    counter for the type of consistency
  354.                    performed, and cleared once the increment
  355.                    is done. */
  356.     int clients = 0;
  357.     int notCaching = 0;
  358.     int writebackFlags;
  359.  
  360.     /*
  361.      * Make sure that noone else is in the middle of performing cache
  362.      * consistency on this file.
  363.      */
  364.     while (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  365.     (void) Sync_Wait(&consistPtr->consistDone, FALSE);
  366.     }
  367.     consistPtr->flags = FS_CONSIST_IN_PROGRESS;
  368.  
  369.     /*
  370.      * Determine cacheability of the file.  Note the system-wide switch
  371.      * to disable client caching.  There are other special cases that
  372.      * are not cached:
  373.      *  1. Swap files are not cached on clients.
  374.      *    2. Non-files, (dirs, links) are not cacheable so we don't have to
  375.      *       worry about keeping them consistent.  (This could be done.)
  376.      *  3. Files that are being concurrently write-shared are not cached.
  377.      *     This includes one writer and one or more readers on other hosts,
  378.      *       and writers on multiple hosts.
  379.      */
  380.     cacheable = fsconsist_ClientCachingEnabled;
  381.     if (useFlags & FS_MIGRATING) {
  382.     countMigration = 1;
  383.     writebackFlags = FSCONSIST_MIGRATION;
  384.     } else {
  385.     countMigration = 0;
  386.     writebackFlags = 0;
  387.     }
  388.     if ((useFlags & FS_SWAP) && (clientID != rpc_SpriteID)) {
  389.     cacheable = FALSE;
  390.     statPtr->swap++;
  391.     } else if (((Fsio_FileIOHandle *)consistPtr->hdrPtr)->descPtr->fileType
  392.             != FS_FILE) {
  393.     cacheable = FALSE;
  394.     statPtr->nonFiles++;
  395.     } else if (useFlags & FS_MAP) {
  396.     cacheable = FALSE;
  397.     }
  398.     if (cacheable) {
  399.     LIST_FORALL(&consistPtr->clientList, (List_Links *)clientPtr) {
  400.         if (clientPtr->mapped) {
  401.         cacheable = FALSE;
  402.         goto done;
  403.         }
  404.         if (clientPtr->clientID != clientID) {
  405.         if ((clientPtr->use.write > 0) ||
  406.             ((clientPtr->use.ref > 0) && openForWriting)) {
  407.             cacheable = FALSE;
  408.             goto done;
  409.         }
  410.         }
  411.     }
  412.     } else {
  413.     countMigration = FALSE;
  414.     }
  415. done:
  416.     /*
  417.      * Now that we know the cacheable state of the file, check the use
  418.      * by other clients, perhaps sending them cache consistency
  419.      * messages.  For each message we send out (the client replies
  420.      * right-away without actually doing anything yet) ClientCommand
  421.      * adds an entry to the consistInfo's message list.  Note also that
  422.      * the current client list entry can get removed as side effects of
  423.      * a call-back so we can't use a simple LIST_FOR_ALL here.
  424.      *
  425.      * Record statistics for both regular opens and migrations.  Migrations
  426.      * are really a subset of regular opens since only some cases can occur.
  427.      */
  428.     statPtr->files++;
  429.     if (countMigration) {
  430.     migStatPtr->consistActions++;
  431.     }
  432.     nextClientPtr = (Fsconsist_ClientInfo *)List_First(&consistPtr->clientList);
  433.     while (!List_IsAtEnd(&consistPtr->clientList, (List_Links *)nextClientPtr)){
  434.     clientPtr = nextClientPtr;
  435.     clientPtr->locked = FALSE;
  436.     nextClientPtr = (Fsconsist_ClientInfo *)List_Next((List_Links *)clientPtr);
  437.     /*
  438.      * Hang onto the next client element across calls to ClientCommand,
  439.      * which releases the consistency lock and may allow client list
  440.      * deletions due to garbage collection.
  441.      */
  442.     if (!List_IsAtEnd(&consistPtr->clientList,(List_Links *)nextClientPtr)){
  443.         nextClientPtr->locked = TRUE;
  444.     }
  445.     if (clientPtr->clientID == clientID) {
  446.         /*
  447.          * Don't call back to the client doing the open.  That can
  448.          * cause deadlock.  Instead, that client takes care of its
  449.          * own cache via the Fscache_UpdateFile procedure.
  450.          */
  451.         if (clientPtr->clientID == consistPtr->lastWriter) {
  452.         statPtr->writeCaching++;
  453.         } else if (clientPtr->use.ref > 0 && clientPtr->cached) {
  454.         statPtr->readCachingMyself++;
  455.         }
  456.         continue;
  457.     }
  458.     clients++;
  459.     if (!clientPtr->cached) {
  460.         /*
  461.          * Case 1, the other client isn't caching the file. Do nothing.
  462.          */
  463.         notCaching++;
  464.     } else if (cacheable) {
  465.         if (consistPtr->lastWriter != clientPtr->clientID) {
  466.         /*
  467.          * Case 2, the other client is caching and it's ok.
  468.          */
  469.         statPtr->readCachingOther++;
  470.         if (countMigration) {
  471.             /*
  472.              * Already caching for reading -- this migration can't
  473.              * change that.
  474.              */
  475.             migStatPtr->readOnlyFiles++;
  476.             countMigration = 0;
  477.         }
  478.         } else if (consistPtr->lastWriter == clientID) {
  479.         /*
  480.          * Case 3, the last writer is now opening for reading.
  481.          * Its dirty cache is ok.  (This case is trapped out above.)
  482.          */
  483.         statPtr->writeCaching++;
  484.         } else {
  485.         int mode;
  486.         /*
  487.          * Case 4, the last writer needs to give us back the
  488.          * dirty blocks so the opening client will get good data.
  489.          * In the case of migration, it is possible for a writable
  490.          * file to be migrated to another host while still being
  491.          * cacheable.  In that case the old client doesn't have
  492.          * any more references to the file and can't use its cached
  493.          * blocks for it anyway.  Since the version number doesn't
  494.          * get incremented due to migration we have to invalidate
  495.          * at migration time.
  496.          */
  497.         mode = FSCONSIST_WRITE_BACK_BLOCKS | writebackFlags;
  498.         if (openForWriting) {
  499.             mode |= FSCONSIST_INVALIDATE_BLOCKS;
  500.         }
  501.         ClientCommand(consistPtr, clientPtr, mode);
  502.         statPtr->writeBack++;
  503.         if (countMigration) {
  504.             migStatPtr->cacheWritableFiles++;
  505.             countMigration = 0;
  506.         }
  507.         }
  508.     } else {
  509.         if ((clientPtr->use.write == 0) && (clientPtr->use.ref > 0)) {
  510.         /*
  511.          * Case 5, another reader needs to stop caching.
  512.          */
  513.         ClientCommand(consistPtr, clientPtr,
  514.                     FSCONSIST_INVALIDATE_BLOCKS);
  515.         statPtr->readInvalidate++;
  516.         } else if (clientPtr->use.write > 0) {
  517.         /*
  518.          * Case 6, the writer needs to stop caching and give
  519.          * us back its dirty blocks.
  520.          */
  521.         ClientCommand(consistPtr, clientPtr,
  522.                   FSCONSIST_WRITE_BACK_BLOCKS |
  523.                   FSCONSIST_INVALIDATE_BLOCKS | writebackFlags);
  524.         statPtr->writeInvalidate++;
  525.         }
  526.         if (countMigration) {
  527.         migStatPtr->cacheToUncacheFiles++;
  528.         countMigration = 0;
  529.         }
  530.     }
  531.     }
  532.     if (cacheable) {
  533.     statPtr->cacheable++;
  534.     if (countMigration) {
  535.         if (notCaching == clients) {
  536.         migStatPtr->uncacheToCacheFiles++;
  537.         } else {
  538.         migStatPtr->readOnlyFiles++;
  539.         }
  540.     }
  541.     } else {
  542.     statPtr->uncacheable++;
  543.     if (countMigration) {
  544.         migStatPtr->uncacheableFiles++;
  545.     }
  546.     }
  547.     statPtr->clients += clients;
  548.     statPtr->notCaching += notCaching;
  549.     *cacheablePtr = cacheable;
  550. }
  551.  
  552. /*
  553.  * ----------------------------------------------------------------------------
  554.  *
  555.  * UpdateList --
  556.  *
  557.  *    Update the state of the client that is using one of our files.
  558.  *    A timestamp is generated for return to the client so it can
  559.  *    catch races between the open return message and cache consistency
  560.  *    messages associated with this file.
  561.  *
  562.  * Results:
  563.  *    The timestamp.
  564.  *
  565.  * Side effects:
  566.  *    The version number is incremented when open for writing.  The
  567.  *    lastWriter is remembered when opening for writing.  Use counts
  568.  *    are kept to reflect the clients use of the file.  Finally,
  569.  *    client list entries for hosts no longer using or caching the
  570.  *    file are deleted.
  571.  *
  572.  * ----------------------------------------------------------------------------
  573.  */
  574.  
  575. INTERNAL void
  576. UpdateList(consistPtr, clientID, useFlags, cacheable, openTimeStampPtr)
  577.     register Fsconsist_Info *consistPtr;/* Consistency state for the file. */
  578.     int            clientID;    /* ID of client using the file */
  579.     int            useFlags;    /* FS_READ|FS_WRITE|FS_EXECUTE */
  580.     Boolean        cacheable;    /* TRUE if client is caching the file */
  581.     int            *openTimeStampPtr;/* Generated for the client so it can
  582.                      * catch races between the return from
  583.                      * this open and other cache messages */
  584. {
  585.     register Fsconsist_ClientInfo *clientPtr;    /* State for other clients */
  586.  
  587.     /*
  588.      * Add the client to the I/O handle client list.
  589.      */
  590.     clientPtr = Fsconsist_IOClientOpen(&consistPtr->clientList, clientID,
  591.         useFlags, cacheable);
  592.  
  593.     if (cacheable && (useFlags & FS_WRITE)) {
  594.     consistPtr->lastWriter = clientID;
  595.     }
  596.     /*
  597.      * Return a time stamp for the open.  This timestamp is used by clients
  598.      * to catch races between the reply message for an open, and a cache
  599.      * consistency message generated from a different open happening at
  600.      * about the same time.
  601.      */
  602.     if (openTimeStampPtr != (int *)NIL) {
  603.     openTimeStamp++;
  604.     *openTimeStampPtr =
  605.         consistPtr->openTimeStamp =
  606.         clientPtr->openTimeStamp = openTimeStamp;
  607.     } else {
  608.     consistPtr->openTimeStamp = clientPtr->openTimeStamp = 0;
  609.     }
  610. }
  611.  
  612.  
  613. /*
  614.  * ----------------------------------------------------------------------------
  615.  *
  616.  * EndConsistency --
  617.  *    Wait for cache consistency actions to complete.
  618.  *
  619.  * Results:
  620.  *    SUCCESS or FS_NO_DISK_SPACE.  We have to abort an open if a client
  621.  *    cannot write back its cache in response to a consistency message.
  622.  *    This only happens if the disk is full.  If the client is down we
  623.  *    won't wait for it.  If it is not really down we treat it as
  624.  *    down and will abort its attempt to re-open later.
  625.  *
  626.  * Side effects:
  627.  *    Notifies the consistDone condition to allow someone else to
  628.  *    open the file.  Clears the FS_CONSIST_IN_PROGRES flag.
  629.  *
  630.  * ----------------------------------------------------------------------------
  631.  *
  632.  */
  633.  
  634. INTERNAL ReturnStatus
  635. EndConsistency(consistPtr)
  636.     Fsconsist_Info    *consistPtr;
  637. {
  638.     register ReturnStatus status;
  639.     Timer_QueueElement timeout;
  640.  
  641.     /*
  642.      * Set up a timeout in case a flakey client can't complete
  643.      * its consistency actions.  We pick an arbitrary "long" interval
  644.      * and just abort after that.  A more complex solution would be
  645.      * to re-iterate what ever high level operation we are doing.
  646.      */
  647.     timeout.routine = ConsistTimeoutIntr;
  648.     timeout.interval = timer_IntOneMinute * fsconsist_TimeoutMinutes;
  649.     timeout.clientData = (ClientData)consistPtr;
  650.     consistPtr->flags |= FS_CONSIST_TIMEOUT;
  651.     Timer_ScheduleRoutine(&timeout, TRUE);
  652.  
  653.     while (!List_IsEmpty(&consistPtr->msgList)) {
  654.     (void) Sync_Wait(&consistPtr->repliesIn, FALSE);
  655.     }
  656.     if (consistPtr->flags & FS_CONSIST_TIMEOUT) {
  657.     (void)Timer_DescheduleRoutine(&timeout);
  658.     consistPtr->flags &= ~FS_CONSIST_TIMEOUT;
  659.     }
  660.     if (consistPtr->flags & FS_CONSIST_ERROR) {
  661.     /*
  662.      * The only reason consistency actions fail altogether is when
  663.      * a client can't do a writeback because there isn't enough
  664.      * disk space here.  Crashed clients don't matter.
  665.      */
  666.     printf("EndConsistency: consistency failed for %s: no disk space\n",
  667.            Fsutil_HandleName(consistPtr->hdrPtr)); /* DEBUG */
  668.     status = FS_NO_DISK_SPACE;
  669.     } else {
  670.     status = SUCCESS;
  671.     }
  672.     consistPtr->flags = 0;
  673.     Sync_Broadcast(&consistPtr->consistDone);
  674.     return(status);
  675. }
  676.  
  677. /*
  678.  *----------------------------------------------------------------------
  679.  *
  680.  * ConsistTimeoutIntr --
  681.  *
  682.  *    Routine called at timer-interrupt time if a client has not
  683.  *    completed consistency actions.  This turns around and does
  684.  *    a Proc_CallFunc to invoke ConsistTimeout at process level.
  685.  *    ConsistTimeout prints a warning and removes the information
  686.  *    about the now aborted consistency request so that the higher-level
  687.  *    operation can complete.
  688.  *
  689.  * Results:
  690.  *    None.
  691.  *
  692.  * Side effects:
  693.  *    Triggers a call to ConsistTimeout, which in turn erases the
  694.  *    consistPtr->msgList and notifies the consistPtr->repliesIn condition.
  695.  *
  696.  *----------------------------------------------------------------------
  697.  */
  698. /*ARGSUSED*/
  699. void
  700. ConsistTimeoutIntr(time, data)
  701.     Timer_Ticks time;    /* The time we timed out at. */
  702.     ClientData data;    /* A pointer to a Fsconsist_Info */
  703. {
  704.     Fsconsist_Info *consistPtr = (Fsconsist_Info *)data;
  705.  
  706.     consistPtr->flags &= ~FS_CONSIST_TIMEOUT;
  707.     Proc_CallFunc(ConsistTimeout, (ClientData)consistPtr, 0);
  708. }
  709.  
  710. void
  711. ConsistTimeout(data, callInfoPtr)
  712.     ClientData        data;    /* A pointer to a Fsconsist_Info */
  713.     Proc_CallInfo    *callInfoPtr;
  714. {
  715.     Fsconsist_Info *consistPtr = (Fsconsist_Info *)data;
  716.     ConsistMsgInfo *msgPtr;
  717.     int ref, write, exec;
  718.  
  719.     LOCK_MONITOR;
  720.     while (!List_IsEmpty(&consistPtr->msgList)) {
  721.     msgPtr = (ConsistMsgInfo *)List_First(&consistPtr->msgList);
  722.  
  723.     printf("ConsistTimeout (%d minutes) client %d %s file <%d,%d> \"%s\"\n",
  724.         fsconsist_TimeoutMinutes,
  725.         msgPtr->clientID, ConsistType(msgPtr->flags),
  726.         consistPtr->hdrPtr->fileID.major,
  727.         consistPtr->hdrPtr->fileID.minor,
  728.         Fsutil_HandleName(consistPtr->hdrPtr));
  729.  
  730.     Fsconsist_IOClientKill(&consistPtr->clientList, msgPtr->clientID,
  731.             &ref, &write, &exec);
  732.     printf("\tClient state killed: %d refs %d write %d exec\n",
  733.             ref, write, exec);
  734.  
  735.     if (msgPtr->clientID == consistPtr->lastWriter) {
  736.         consistPtr->lastWriter = -1;
  737.     }
  738.     List_Remove((List_Links *)msgPtr);
  739.     free((Address)msgPtr);
  740.     }
  741.     Sync_Broadcast(&consistPtr->repliesIn);
  742.     callInfoPtr->interval = 0;    /* No more invocations, please */
  743.     UNLOCK_MONITOR;
  744. }
  745.  
  746.  
  747. /*
  748.  * ----------------------------------------------------------------------------
  749.  *
  750.  * Fsconsist_ReopenClient --
  751.  *
  752.  *    Conflict checking has already been done for the re-open, and this
  753.  *    routine updates global use counts and the client list so that
  754.  *    regular opens know the file is being used.  This is called with
  755.  *    the handle locked and it also grabs the consistency monitor lock
  756.  *    to update the client list.
  757.  *    Consistency call-backs are made    later by Fsconsist_ReopenConsistency.
  758.  *
  759.  * Results:
  760.  *    None.
  761.  *
  762.  * Side effects:
  763.  *    Updates the global use counts of the file, the last writer of
  764.  *    the file, and the client list entry for this client.  Note that
  765.  *    by updating the lastWriter here we may cause a call-back to
  766.  *    the re-opening client during Fsconsist_ReopenConsistency.  This is the
  767.  *    best we can do if another client has slipped in and opened
  768.  *    for reading already.
  769.  *
  770.  * ----------------------------------------------------------------------------
  771.  */
  772. ENTRY void
  773. Fsconsist_ReopenClient(handlePtr, clientID, use, haveDirtyBlocks)
  774.     Fsio_FileIOHandle    *handlePtr;    /* Should be LOCKED. */
  775.     int            clientID;    /* The client who is opening the file.*/
  776.     Fsio_UseCounts        use;        /* Clients usage of the file */
  777.     Boolean         haveDirtyBlocks;/* TRUE if client expects it to be
  778.                      * cacheable because it has
  779.                      * outstanding dirty blocks. */
  780. {
  781.     register Fsconsist_Info    *consistPtr = &handlePtr->consist;
  782.     register Fsconsist_ClientInfo    *clientPtr;
  783.     Boolean            found;
  784.  
  785.     LOCK_MONITOR;
  786.  
  787.     found = FALSE;
  788.     LIST_FORALL(&(consistPtr->clientList), (List_Links *)clientPtr) {
  789.     if (clientPtr->clientID == clientID) {
  790.         found = TRUE;
  791.         handlePtr->use.ref   += use.ref   - clientPtr->use.ref;
  792.         handlePtr->use.write += use.write - clientPtr->use.write;
  793.         handlePtr->use.exec  += use.exec  - clientPtr->use.exec;
  794.         clientPtr->use = use;
  795.         clientPtr->cached = haveDirtyBlocks;
  796.         if ((handlePtr->use.ref < 0) || (handlePtr->use.write < 0) ||
  797.             (handlePtr->use.exec < 0)) {
  798.         panic("Fsconsist_ReopenClient: client %d ref %d write %d exec %d\n" ,
  799.             clientID,
  800.             handlePtr->use.ref, handlePtr->use.write,
  801.             handlePtr->use.exec);
  802.         }
  803.     } else if ((clientPtr->use.ref > 0) && haveDirtyBlocks) {
  804.         /*
  805.          * Oops, another client is reading this file but the re-opening
  806.          * client has dirty blocks for it.  We've already checked the
  807.          * version number so we know another client isn't writing.
  808.          * We allow this conflict to happen - the regular cache
  809.          * consistency routines will tell the reading client to
  810.          * stop caching, and the writing client will write-back
  811.          * its blocks as soon as possible.  This leaves a window
  812.          * for inconsistent reads, but the outstanding dirty blocks
  813.          * are not lost.
  814.          */
  815.         printf("FsReopenHandle: file \"%s\" <%d,%d>: client %d has dirty blocks, but client %d is using\n",
  816.         Fsutil_HandleName(handlePtr),
  817.         handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
  818.         clientID, clientPtr->clientID);
  819.     }
  820.     }
  821.     if (!found) {
  822.     INSERT_CLIENT(&consistPtr->clientList, clientPtr, clientID);
  823.     clientPtr->use = use;
  824.     clientPtr->cached = haveDirtyBlocks;
  825.  
  826.     handlePtr->use.ref   += use.ref;
  827.     handlePtr->use.write += use.write;
  828.     handlePtr->use.exec  += use.exec;
  829.     }
  830.     if (haveDirtyBlocks) {
  831.     if (consistPtr->lastWriter != -1 &&
  832.         consistPtr->lastWriter != clientID) {
  833.         /*
  834.          * Version number checking should have prevented this.
  835.          */
  836.         printf("FsReopenHandle: file \"%s\" <%d,%d>: Client %d with dirty blocks not last writer %d\n",
  837.         Fsutil_HandleName(handlePtr),
  838.         handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
  839.         clientID, consistPtr->lastWriter);
  840.     } else {
  841.         consistPtr->lastWriter = clientID;
  842.     }
  843.     } else if (consistPtr->lastWriter == clientID) {
  844.     consistPtr->lastWriter = -1;
  845.     }
  846.     UNLOCK_MONITOR;
  847. }
  848.  
  849. /*
  850.  * ----------------------------------------------------------------------------
  851.  *
  852.  * Fsconsist_ReopenConsistency --
  853.  *
  854.  *    Perform cache consistency actions for a file that the client had 
  855.  *    open before we crashed.  This is similar to regular cache consistency,
  856.  *    except that the client list has already been updated by
  857.  *    Fsconsist_ReopenClient.  This can result in a call-back to the
  858.  *    re-opening client asking to write back its version of the file.
  859.  *
  860.  * Results:
  861.  *    TRUE if could provide the cacheability expected, FALSE otherwise.
  862.  *
  863.  * Side effects:
  864.  *    *cacheablePtr is TRUE if the file is to be cached by the client.
  865.  *    *openTimeStampPtr is set for use by clients.  They keep this timestamp
  866.  *    in order to catch races between the return from their open request
  867.  *    (which we are part of) and cache consistency messages resulting from
  868.  *    opens occuring at about the same time.
  869.  *
  870.  * ----------------------------------------------------------------------------
  871.  */
  872. ENTRY ReturnStatus
  873. Fsconsist_ReopenConsistency(handlePtr, clientID, use, swap, cacheablePtr,
  874.     openTimeStampPtr)
  875.     Fsio_FileIOHandle    *handlePtr;    /* Should be UNLOCKED. */
  876.     int            clientID;    /* The client who is opening the file.*/
  877.     Fsio_UseCounts    use;        /* Clients usage of the file */
  878.     int            swap;        /* 0 or FS_SWAP to indicate swap file.*/
  879.     Boolean         *cacheablePtr;    /* IN: TRUE if client expects it to be
  880.                      * cacheable, i.e. has dirty blocks.
  881.                      * OUT: Cacheability of the file. */
  882.     int            *openTimeStampPtr; /* Place to return a timestamp for 
  883.                      * this open.*/
  884. {
  885.     int                useFlags;
  886.     Boolean            cacheable;
  887.     ReturnStatus        status;
  888.     register Fsconsist_Info    *consistPtr = &handlePtr->consist;
  889.     register Fsconsist_ClientInfo    *clientPtr;
  890.  
  891.     LOCK_MONITOR;
  892.  
  893.     useFlags = swap;
  894.     if (use.ref > use.write + use.exec) {
  895.     useFlags |= FS_READ;
  896.     }
  897.     if (use.write > 0 || *cacheablePtr) {
  898.     useFlags |= FS_WRITE;
  899.     }
  900.     if (use.exec > 0) {
  901.     useFlags |= FS_EXECUTE;
  902.     }
  903.  
  904.     if (useFlags == 0) {
  905.     /*
  906.      * The client isn't using the file anymore so clean up state.
  907.      */
  908.     LIST_FORALL(&(consistPtr->clientList), (List_Links *)clientPtr) {
  909.         if (clientPtr->clientID == clientID) {
  910.         REMOVE_CLIENT(clientPtr);
  911.         break;
  912.         }
  913.     }
  914.     *openTimeStampPtr = consistPtr->openTimeStamp;
  915.     *cacheablePtr = FALSE;
  916.     status = SUCCESS;
  917.     } else {
  918.     StartConsistency(consistPtr, clientID, useFlags, &cacheable);
  919.  
  920.     /*
  921.      * Get a new openTimeStamp so the client can detect races between
  922.      * the reopen return and consistency messages generated by other
  923.      * opens happening right now (or real soon).
  924.      * FIX ME.  The file version number should be used instead.
  925.      */
  926.     openTimeStamp++;
  927.     *openTimeStampPtr = consistPtr->openTimeStamp = openTimeStamp;
  928.     /*
  929.      * Mark the client as caching or not.
  930.      */
  931.     *cacheablePtr = cacheable;
  932.     if ((useFlags & FS_WRITE) && cacheable) {
  933.         consistPtr->lastWriter = clientID;
  934.     }
  935.     /*
  936.      * We are careful to search for the client list entry again
  937.      * because it might go away during concurrent operations.
  938.      */
  939.     LIST_FORALL(&consistPtr->clientList, (List_Links *)clientPtr) {
  940.         if (clientPtr->clientID == clientID) {
  941.         clientPtr->openTimeStamp = openTimeStamp;
  942.         clientPtr->cached = cacheable;
  943.         break;
  944.         }
  945.     }
  946.     /*
  947.      * Wait for cache consistency call-backs to complete.
  948.      */
  949.     status = EndConsistency(consistPtr);
  950.     }
  951.     UNLOCK_MONITOR;
  952.     return(status);
  953. }
  954.  
  955. /*
  956.  * ----------------------------------------------------------------------------
  957.  *
  958.  * Fsconsist_MigrateConsistency --
  959.  *
  960.  *    Shift the references on a file from one client to another.  If
  961.  *    the stream to this handle is not shared across network this
  962.  *    is done by first removing the useCounts due to the srcClient,
  963.  *    and them performing the regular cache consistency algorithm as
  964.  *    if the dstClient is opening the file.  If the stream is shared
  965.  *    things are more complicated.  We must not close the original
  966.  *    client until all stream references to its I/O handle have migrated,
  967.  *    and we must be careful to not add too many references to the
  968.  *    new client.
  969.  *
  970.  * Results:
  971.  *    SUCCESS, unless there is a cache consistency conflict detected.
  972.  *
  973.  * Side effects:
  974.  *    The HANDLE RETURNS UNLOCKED.  Also, full-fledged cache consistency
  975.  *    actions are taken.
  976.  *
  977.  * ----------------------------------------------------------------------------
  978.  */
  979.  
  980. ENTRY ReturnStatus
  981. Fsconsist_MigrateConsistency(handlePtr, srcClientID, dstClientID, useFlags,
  982.     closeSrc, cacheablePtr, openTimeStampPtr)
  983.     Fsio_FileIOHandle    *handlePtr;    /* Needs to be UNLOCKED  */
  984.     int            srcClientID;    /* ID of client using the file */
  985.     int            dstClientID;    /* ID of client using the file */
  986.     int            useFlags;    /* FS_READ|FS_WRITE|FS_EXECUTE
  987.                      * FS_RMT_SHARED if shared now.
  988.                      * FS_NEW_STREAM if dstClientID is
  989.                      * getting stream for first time.
  990.                      * FS_MIGRATED_FILE is set to tell
  991.                      * the low-level consistency routines
  992.                      * to record statistics. */
  993.     Boolean        closeSrc;    /* TRUE if should close source client.
  994.                      * Set by Fsio_StreamMigClient */
  995.     Boolean        *cacheablePtr;    /* Return - Cachability of file */
  996.     int            *openTimeStampPtr;/* Generated for the client so it can
  997.                      * catch races between the return from
  998.                      * this open and other cache messages */
  999. {
  1000.     register Fsconsist_Info *consistPtr = &handlePtr->consist;
  1001.     Boolean            cache;
  1002.     register    ReturnStatus    status;
  1003.  
  1004.     LOCK_MONITOR;
  1005.  
  1006.     cache = (srcClientID == consistPtr->lastWriter);
  1007.  
  1008.     if (closeSrc) {
  1009.     /*
  1010.      * Remove references due to the original client so it doesn't confuse
  1011.      * the regular cache consistency algorithm.  Note that this call
  1012.      * doesn't disturb the last writer state so any dirty blocks on
  1013.      * the old client will get handled properly.
  1014.      */
  1015.     if (!Fsconsist_IOClientClose(&consistPtr->clientList, srcClientID,
  1016.                      useFlags, &cache)) {
  1017.         printf("Fsconsist_MigrateConsistency, srcClient %d unknown for %s %s <%d,%d>\n",
  1018.         srcClientID,
  1019.         Fsutil_FileTypeToString(handlePtr->hdr.fileID.type),
  1020.         Fsutil_HandleName(handlePtr),
  1021.         handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor);
  1022.     }
  1023.     }
  1024.     /*
  1025.      * The rest of this is like regular cache consistency.
  1026.      */
  1027.  
  1028.     StartConsistency(consistPtr, dstClientID, (int) (useFlags | FS_MIGRATING),
  1029.              cacheablePtr);
  1030.     if (useFlags & FS_NEW_STREAM) {
  1031.     /*
  1032.      * The client is getting the stream to this I/O handle for
  1033.      * the first time so we should add it as a client.  We are
  1034.      * careful about this because there is only one reference to
  1035.      * the I/O handle per client per stream. 
  1036.      */
  1037.     UpdateList(consistPtr, dstClientID, useFlags, *cacheablePtr,
  1038.             openTimeStampPtr);
  1039.     }
  1040.     status = EndConsistency(consistPtr);
  1041.  
  1042.     UNLOCK_MONITOR;
  1043.     return(status);
  1044. }
  1045.  
  1046.  
  1047. /*
  1048.  * ----------------------------------------------------------------------------
  1049.  *
  1050.  * Fsconsist_GetClientAttrs --
  1051.  *
  1052.  *    This does call-backs to clients to flush back cached attributes.
  1053.  *    Files that are being executed are treated as a special case.  They
  1054.  *    are not being written so we, the server, have the right size and
  1055.  *    modify time.  Instead of getting access times from clients (there
  1056.  *    could be lots and lots) we just return a flag that says the
  1057.  *    file is being executed.  Our caller will presumably use the
  1058.  *    the current time for the access time in this case.
  1059.  *
  1060.  * Results:
  1061.  *    *isExecedPtr set to TRUE if the file is being executed.
  1062.  *
  1063.  * Side effects:
  1064.  *      RPC's may be done to clients using the file to tell them to write
  1065.  *    back their cached attributes.
  1066.  *    This unlocks the handle while waiting for clients, but
  1067.  *    re-locks it before returning.
  1068.  *
  1069.  * ----------------------------------------------------------------------------
  1070.  */
  1071. ENTRY void
  1072. Fsconsist_GetClientAttrs(handlePtr, clientID, isExecedPtr)
  1073.     register Fsio_FileIOHandle *handlePtr;
  1074.     int            clientID;    /* The client who is doing the stat.*/
  1075.     Boolean        *isExecedPtr;    /* TRUE if file is being executed.
  1076.                      * Our caller will use the current
  1077.                      * time for the access time in this
  1078.                      * case */
  1079. {
  1080.     register Boolean        isExeced = FALSE;
  1081.     register Fsconsist_Info    *consistPtr = &handlePtr->consist;
  1082.     register Fsconsist_ClientInfo    *clientPtr;
  1083.     register Fsconsist_ClientInfo    *nextClientPtr;
  1084.  
  1085.     /*
  1086.      * Unlock the handle so other operations on the file can proceed while
  1087.      * we probe around the network for the most up-to-date attributes.
  1088.      * Otherwise the following deadlock is possible:
  1089.      * Client 1 does a get attributes about the same time client 2 does
  1090.      * a close.  Client 2 has its handle locked during the close, but we
  1091.      * will be calling back to it to get its attributes.  Our callback can't
  1092.      * start until client 2 unlocks its handle, but it can't unlock it's
  1093.      * handle until the close finishes.  The close can't finish because
  1094.      * it is blocked here on the locked handle.
  1095.      */
  1096.  
  1097.     Fsutil_HandleUnlock(handlePtr);
  1098.     LOCK_MONITOR;
  1099.  
  1100.     /*
  1101.      * Make sure that noone else is in the middle of performing cache
  1102.      * consistency on this handle.  If so wait until they are done.
  1103.      */
  1104.     while (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1105.     (void) Sync_Wait(&consistPtr->consistDone, FALSE);
  1106.     }
  1107.     consistPtr->flags = FS_CONSIST_IN_PROGRESS;
  1108.  
  1109.     /*
  1110.      * Go through the set of clients using the file and see if they
  1111.      * are caching attributes.
  1112.      */
  1113.     nextClientPtr = (Fsconsist_ClientInfo *)List_First(&consistPtr->clientList);
  1114.     while (!List_IsAtEnd(&consistPtr->clientList, (List_Links *)nextClientPtr)){
  1115.     clientPtr = nextClientPtr;
  1116.     clientPtr->locked = FALSE;;
  1117.     nextClientPtr = (Fsconsist_ClientInfo *)List_Next((List_Links *)clientPtr);
  1118.     /*
  1119.      * Hang onto the next client list element across calls to ClientCommand,
  1120.      * which releases the consistency lock and allows list deletions.
  1121.      */
  1122.     if (!List_IsAtEnd(&consistPtr->clientList,(List_Links *)nextClientPtr)){
  1123.         nextClientPtr->locked = TRUE;
  1124.     }
  1125.     if (clientPtr->use.exec > 0) {
  1126.         isExeced = TRUE;
  1127.     }
  1128.     if ((clientPtr->cached) && (clientPtr->use.ref > 0)) {
  1129.         if ((clientPtr->clientID != clientID) &&
  1130.         (clientPtr->use.exec == 0)) {
  1131.         /*
  1132.          * Don't call back to our caller because it will check
  1133.          * its own attributes later.  Also, don't send rpcs to
  1134.          * clients executing files.  For these clients we just
  1135.          * set the access time to the current time.  This
  1136.          * is an optimization to not make stating of binaries
  1137.          * abysmally slow.
  1138.          */
  1139.  
  1140.         ClientCommand(consistPtr, clientPtr, FSCONSIST_WRITE_BACK_ATTRS);
  1141.         }
  1142.     }
  1143.     }
  1144.     /*
  1145.      * Now that we are all set up, and have told all the other clients using
  1146.      * the file what they have to do, we wait for them to finish.
  1147.      */
  1148.     (void)EndConsistency(consistPtr);
  1149.  
  1150.     *isExecedPtr = isExeced;
  1151.     UNLOCK_MONITOR;
  1152.     Fsutil_HandleLock(handlePtr);
  1153. }
  1154.  
  1155. /*
  1156.  * ----------------------------------------------------------------------------
  1157.  *
  1158.  * Fsconsist_Close --
  1159.  *
  1160.  *    A thin layer on top of Fsconsist_IOClientClose that also cleans up
  1161.  *    the last writer of a file.
  1162.  *
  1163.  * Results:
  1164.  *    TRUE if there was a record that the client was using the file.
  1165.  *    This is used to trap out invalid closes.  Also, *wasCachedPtr
  1166.  *    is set to TRUE if the file (in particular, its attributes) was
  1167.  *    cached on the client.
  1168.  *
  1169.  * Side effects:
  1170.  *    The client list entry is removed.  If the client was
  1171.  *    the last writer but has no dirty blocks (as indicated by the flags)
  1172.  *    then the last writer field of the consist info is cleared.
  1173.  *
  1174.  * ----------------------------------------------------------------------------
  1175.  *
  1176.  */
  1177. ENTRY Boolean
  1178. Fsconsist_Close(consistPtr, clientID, flags, wasCachedPtr)
  1179.     register Fsconsist_Info *consistPtr;    /* Handle of file being closed */
  1180.     int            clientID;    /* Host ID of client that had it open */
  1181.     register int    flags;        /* Flags from the stream. */
  1182.     Boolean        *wasCachedPtr;    /* TRUE upon return if the client was
  1183.                      * caching (attributes) of the file. */
  1184. {
  1185.     LOCK_MONITOR;
  1186.  
  1187.     *wasCachedPtr = (consistPtr->lastWriter == clientID);
  1188.     if (!Fsconsist_IOClientClose(&consistPtr->clientList, clientID, flags,
  1189.              wasCachedPtr)) {
  1190.     UNLOCK_MONITOR;
  1191.     return(FALSE);
  1192.     }
  1193.  
  1194.     if ((consistPtr->lastWriter != -1) && (flags & FS_LAST_DIRTY_BLOCK)) {
  1195.         if (clientID != consistPtr->lastWriter) {
  1196.             /*
  1197.              * Probably a client error with the lastWriter.  We print
  1198.              * a warning and then nuke the lastWriter field below.
  1199.              */
  1200.             printf("%s, \"%s\" <%d,%d>: client %d not last writer %d, %s\n",
  1201.                     "Fsconsist_Close",
  1202.                     Fsutil_HandleName(consistPtr->hdrPtr),
  1203.                     consistPtr->hdrPtr->fileID.major,
  1204.                     consistPtr->hdrPtr->fileID.minor,
  1205.                     clientID, consistPtr->lastWriter,
  1206.                     (*wasCachedPtr) ? "was cached" : "wasn't cached");
  1207.         }
  1208.         consistPtr->lastWriter = -1;
  1209.     }
  1210.  
  1211.     UNLOCK_MONITOR;
  1212.     return(TRUE);
  1213. }
  1214.  
  1215.  
  1216. /*
  1217.  * ----------------------------------------------------------------------------
  1218.  *
  1219.  * Fsconsist_NumClients --
  1220.  *
  1221.  *    Returns the number of clients in the client list for a file.
  1222.  *    Called to see if it's ok to scavenge the file handle.
  1223.  *
  1224.  * Results:
  1225.  *    The number of clients in the client list.
  1226.  *
  1227.  * Side effects:
  1228.  *    Unused client list entries are cleaned up.  We only need to remember
  1229.  *    clients that are actively using the file or who have dirty blocks
  1230.  *    because they are the last writer.
  1231.  *
  1232.  * ----------------------------------------------------------------------------
  1233.  *
  1234.  */
  1235.  
  1236. ENTRY int
  1237. Fsconsist_NumClients(consistPtr)
  1238.     register Fsconsist_Info *consistPtr;    /* Handle of file being closed */
  1239. {
  1240.     register int numClients = 0;
  1241.     register Fsconsist_ClientInfo *clientPtr;
  1242.     register Fsconsist_ClientInfo *nextClientPtr;
  1243.  
  1244.     LOCK_MONITOR;
  1245.  
  1246.     if (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1247.     /*
  1248.      * Not safe to mess with list during consistency.
  1249.      */
  1250.     numClients = 1;
  1251.     goto exit;
  1252.     }
  1253.     nextClientPtr = (Fsconsist_ClientInfo *)List_First(&consistPtr->clientList);
  1254.     while (!List_IsAtEnd(&consistPtr->clientList, (List_Links *)nextClientPtr)){
  1255.     clientPtr = nextClientPtr;
  1256.     nextClientPtr = (Fsconsist_ClientInfo *)List_Next((List_Links *)clientPtr);
  1257.     /*
  1258.      * Nuke the client list entry if the client isn't using the file now,
  1259.      * and it isn't a remote client holding dirty blocks,
  1260.      * and this element isn't locked by another process doing consistency.
  1261.      */
  1262.     if (clientPtr->use.ref == 0 &&
  1263.         ((clientPtr->clientID == rpc_SpriteID) || 
  1264.          (clientPtr->clientID != consistPtr->lastWriter)) &&
  1265.         !clientPtr->locked) {
  1266.         REMOVE_CLIENT(clientPtr);
  1267.     } else {
  1268.         numClients++;
  1269.     }
  1270.     }
  1271. exit:
  1272.     UNLOCK_MONITOR;
  1273.     return(numClients);
  1274. }
  1275.  
  1276.  
  1277. /*
  1278.  * ----------------------------------------------------------------------------
  1279.  *
  1280.  * Fsconsist_DeleteLastWriter --
  1281.  *
  1282.  *    Remove the last writer from the consistency list.  This is called
  1283.  *    from the write rpc stub when the last block of a file comes
  1284.  *    in from a remote client.
  1285.  *
  1286.  * Results:
  1287.  *    None.
  1288.  *
  1289.  * Side effects:
  1290.  *    Removes the client list entry for the last writer if the last
  1291.  *    writer is no longer using the file.
  1292.  *
  1293.  * ----------------------------------------------------------------------------
  1294.  *
  1295.  */
  1296. ENTRY void
  1297. Fsconsist_DeleteLastWriter(consistPtr, clientID)
  1298.     Fsconsist_Info *consistPtr;
  1299.     int        clientID;
  1300. {
  1301.     register    Fsconsist_ClientInfo    *clientPtr;
  1302.  
  1303.     LOCK_MONITOR;
  1304.  
  1305.     if (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1306.     /*
  1307.      * Not safe to mess with the list during consistency.  We are called
  1308.      * from Fsrmt_RpcWrite on the client's last block, but we will
  1309.      * delete the last writer in ProcessConsistReply if the write-back
  1310.      * is forced as part of cache consistency.
  1311.      */
  1312.     UNLOCK_MONITOR;
  1313.     return;
  1314.     }
  1315.     LIST_FORALL(&consistPtr->clientList, (List_Links *) clientPtr) {
  1316.     if (clientPtr->clientID == clientID) {
  1317.         if (clientPtr->use.ref == 0 &&
  1318.         consistPtr->lastWriter == clientID) {
  1319.         if (!clientPtr->locked) {
  1320.             Fsrecov_HandleState    recovInfo;
  1321.             ReturnStatus    status;
  1322.  
  1323.             REMOVE_CLIENT(clientPtr);
  1324.             /*
  1325.              * If the handle had a 0 ref count but was still in the
  1326.              * recovery box due to having dirty blocks in the client's
  1327.              * cache, we can now get rid of it.
  1328.              */
  1329.             if (recov_Transparent &&
  1330.                 Fsrecov_GetHandle(consistPtr->hdrPtr->fileID,
  1331.                 clientID, &recovInfo, FALSE) == SUCCESS) {
  1332.             if (recovInfo.use.ref <= 0) {
  1333.                 status = Fsrecov_DeleteHandle(consistPtr->hdrPtr,
  1334.                     clientID, FS_WRITE | FS_LAST_DIRTY_BLOCK);
  1335.                 if (status != SUCCESS) {
  1336.                 /* Should I panic? */
  1337.                 printf("Fsconsist_ClientRemoveCallback: couldn't ");
  1338.                 printf("delete handle from recov box.\n");
  1339.                 }
  1340.             } else {
  1341.                 printf("Fsconsist_ClientRemoveCallback: ref count ");
  1342.                 panic("on object is too high.");
  1343.             }
  1344.             }
  1345.         }
  1346.         consistPtr->lastWriter = -1;
  1347.         break;
  1348.         }
  1349.     }
  1350.     }
  1351.     UNLOCK_MONITOR;
  1352. }
  1353.  
  1354. /*
  1355.  * ----------------------------------------------------------------------------
  1356.  *
  1357.  * Fsconsist_ClientRemoveCallback --
  1358.  *
  1359.  *      Called when a file is deleted.  Send an rpc to the client who has
  1360.  *      dirty blocks cached telling it to delete them from its cache.
  1361.  *    We may have forgotten about clients with clean blocks so we can't
  1362.  *    call them back.  Instead we depend on the version number being
  1363.  *    incremented to catch old blocks left in caches.  There are two
  1364.  *    reasons to tell the last writer - first, it prevents needless
  1365.  *    write-backs, which consumes our CPU, and it is nice to the client
  1366.  *    because it can make room in its cache by deleting the file.
  1367.  *
  1368.  * Results:
  1369.  *    None.
  1370.  *
  1371.  * Side effects:
  1372.  *    Any remotely cached dirty data is invalidated.
  1373.  *    All the entries in the client list are deleted.
  1374.  *
  1375.  * ----------------------------------------------------------------------------
  1376.  *
  1377.  */
  1378. ENTRY void
  1379. Fsconsist_ClientRemoveCallback(consistPtr, clientID)
  1380.     Fsconsist_Info *consistPtr;    /* File to check */
  1381.     int        clientID;    /* Client who is removing the file.  This
  1382.                  * host is not contacted via call-back.
  1383.                  * Instead, the current RPC (close) should
  1384.                  * return FS_FILE_REMOVED.  Note, a callback
  1385.                  * is made during a remove-by-name. */
  1386. {
  1387.     register    Fsconsist_ClientInfo    *clientPtr;
  1388.     int                curClientID;
  1389.  
  1390.     Fsutil_HandleUnlock(consistPtr->hdrPtr);
  1391.  
  1392.     LOCK_MONITOR;
  1393.  
  1394.     while (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1395.     (void) Sync_Wait(&consistPtr->consistDone, FALSE);
  1396.     }
  1397.     consistPtr->flags = FS_CONSIST_IN_PROGRESS;
  1398.  
  1399.     /*
  1400.      * Loop through the list notifying clients and deleting client elements.
  1401.      */
  1402.     while (!List_IsEmpty((List_Links *)&consistPtr->clientList)) {
  1403.     clientPtr = (Fsconsist_ClientInfo *)
  1404.             List_First((List_Links *) &consistPtr->clientList);
  1405.     curClientID = clientPtr->clientID;
  1406.     if (clientPtr->use.ref > 0) {
  1407.         printf("Fsconsist_ClientRemoveCallback: Client %d using removed file <%s>\n",
  1408.         curClientID, Fsutil_HandleName(consistPtr->hdrPtr));
  1409.     } else if (consistPtr->lastWriter != -1) {
  1410.         if (clientPtr->clientID != consistPtr->lastWriter) {
  1411.         printf("Fsconsist_ClientRemoveCallback: \"%s\" <%d,%d> client %d not last writer (%d).\n",
  1412.             Fsutil_HandleName(consistPtr->hdrPtr),
  1413.             consistPtr->hdrPtr->fileID.major,
  1414.             consistPtr->hdrPtr->fileID.minor,
  1415.             clientPtr->clientID, consistPtr->lastWriter);
  1416.         } else if (clientPtr->clientID != clientID) {
  1417.         Fsrecov_HandleState    recovInfo;
  1418.         ReturnStatus        status;
  1419.         /*
  1420.          * Tell the client caching the file to remove it from its cache.
  1421.          * This should only be the last writer as we are called only
  1422.          * when it is truely time to remove the file.
  1423.          */
  1424.         ClientCommand(consistPtr, clientPtr, FSCONSIST_DELETE_FILE);
  1425.         (void)EndConsistency(consistPtr);
  1426.         /*
  1427.          * If the handle had a 0 ref count but was still in the
  1428.          * recovery box due to having dirty blocks in the client's
  1429.          * cache, we can now get rid of it.
  1430.          */
  1431.         if (recov_Transparent &&
  1432.             Fsrecov_GetHandle(consistPtr->hdrPtr->fileID,
  1433.             clientPtr->clientID, &recovInfo, FALSE) == SUCCESS) {
  1434.             if (recovInfo.use.ref <= 0) {
  1435.             status = Fsrecov_DeleteHandle(consistPtr->hdrPtr,
  1436.                 clientPtr->clientID,
  1437.                 FS_WRITE | FS_LAST_DIRTY_BLOCK);
  1438.             if (status != SUCCESS) {
  1439.                 /* Should I panic? */
  1440.                 printf("Fsconsist_ClientRemoveCallback: couldn't ");
  1441.                 printf("delete handle from recov box.\n");
  1442.             }
  1443.             }
  1444.         }
  1445.         }
  1446.     }
  1447.     /*
  1448.      * We have to check carefully that the client element is still
  1449.      * here because it may already be removed by ClientKill.
  1450.      */
  1451.     LIST_FORALL((List_Links *)&consistPtr->clientList,
  1452.             (List_Links *)clientPtr) {
  1453.         if (clientPtr->clientID == curClientID) {
  1454.         REMOVE_CLIENT(clientPtr);
  1455.         break;
  1456.         }
  1457.     }
  1458.     }
  1459.     consistPtr->flags = 0;
  1460.     consistPtr->lastWriter = -1;
  1461.     UNLOCK_MONITOR;
  1462.     Fsutil_HandleLock(consistPtr->hdrPtr);
  1463. }
  1464.  
  1465. /*
  1466.  * ----------------------------------------------------------------------------
  1467.  *
  1468.  * Fsconsist_Kill --
  1469.  *
  1470.  *    Find and remove the given client in the list for the handle.  The
  1471.  *    number of client references, writers, and executers is returned
  1472.  *    so our caller can clean up the reference counts in the handle.
  1473.  *
  1474.  * Results:
  1475.  *    *inUsePtr set to TRUE if the client has the file open, *writingPtr
  1476.  *    set to TRUE if the client has the file open for writing, and 
  1477.  *    *executingPtr set to TRUE if the client has the file open for
  1478.  *    execution.
  1479.  *    
  1480.  * Side effects:
  1481.  *    If this client was the last writer for the file then the last
  1482.  *    writer field in the handle is set to -1.
  1483.  *
  1484.  * ----------------------------------------------------------------------------
  1485.  *
  1486.  */
  1487. ENTRY void
  1488. Fsconsist_Kill(consistPtr, clientID, refPtr, writePtr, execPtr)
  1489.     Fsconsist_Info *consistPtr;    /* Consistency state from which to remove
  1490.                  * the client. */
  1491.     int        clientID;    /* Client to delete. */
  1492.     int        *refPtr;    /* Number of times client has file open. */
  1493.     int        *writePtr;    /* Number of times client is writing file. */
  1494.     int        *execPtr;    /* Number of times clients is executing file.*/
  1495. {
  1496.     register ConsistMsgInfo     *msgPtr;
  1497.  
  1498.     LOCK_MONITOR;
  1499.  
  1500.     Fsconsist_IOClientKill(&consistPtr->clientList, clientID, refPtr, writePtr,
  1501.             execPtr);
  1502.  
  1503.     if (consistPtr->lastWriter == clientID) {
  1504.     consistPtr->lastWriter = -1;
  1505.     }
  1506.     /*
  1507.      * Remove the client from the list of clients involved in a cache
  1508.      * consistency action so we don't hang on the dead client.
  1509.      */
  1510.     LIST_FORALL(&(consistPtr->msgList), (List_Links *) msgPtr) {
  1511.     if (msgPtr->clientID == clientID) {
  1512.         List_Remove((List_Links *) msgPtr);
  1513.         free((Address) msgPtr);
  1514.         Sync_Broadcast(&consistPtr->repliesIn);
  1515.         break;
  1516.     }
  1517.     }
  1518.  
  1519.     UNLOCK_MONITOR;
  1520. }
  1521.  
  1522. /*
  1523.  *----------------------------------------------------------------------------
  1524.  *
  1525.  * Fsconsist_GetAllDirtyBlocks --
  1526.  *
  1527.  *    Retrieve dirty blocks from all clients that have files open on the
  1528.  *    given domain.  This is called when a disk is being detached.  We
  1529.  *    have to get any outstanding data before taking the disk off-line.
  1530.  *
  1531.  * Results:
  1532.  *    None.
  1533.  *
  1534.  * Side effects:
  1535.  *    None.
  1536.  *
  1537.  *----------------------------------------------------------------------------
  1538.  */
  1539. void
  1540. Fsconsist_GetAllDirtyBlocks(domain, invalidate)
  1541.     int        domain;        /* Domain to get dirty blocks for. */
  1542.     Boolean    invalidate;    /* Remove file from cache after getting blocks
  1543.                  * back. */
  1544. {
  1545.     Hash_Search                hashSearch;
  1546.     register    Fs_HandleHeader        *hdrPtr;
  1547.  
  1548.     Hash_StartSearch(&hashSearch);
  1549.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  1550.      hdrPtr != (Fs_HandleHeader *) NIL;
  1551.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  1552.     if (hdrPtr->fileID.type == FSIO_LCL_FILE_STREAM &&
  1553.         hdrPtr->fileID.major == domain) {
  1554.         register Fsio_FileIOHandle *handlePtr =
  1555.             (Fsio_FileIOHandle *) hdrPtr;
  1556.         Fsconsist_FetchDirtyBlocks(&handlePtr->consist, invalidate);
  1557.     }
  1558.     Fsutil_HandleUnlock(hdrPtr);
  1559.     }
  1560. }
  1561.  
  1562. /*
  1563.  * ----------------------------------------------------------------------------
  1564.  *
  1565.  * Fsconsist_FetchDirtyBlocks --
  1566.  *
  1567.  *      Fetch dirty blocks back from the last writer of the file.
  1568.  *    This is called when a domain is being detached (dis-mounted)
  1569.  *    and we want all dirty data to be written back first.
  1570.  *
  1571.  * Results:
  1572.  *    None.
  1573.  *
  1574.  * Side effects:
  1575.  *    If the last writer doesn't have the file actively open, then it is
  1576.  *    no longer the last writer and it is deleted from the client list.
  1577.  *
  1578.  * ----------------------------------------------------------------------------
  1579.  *
  1580.  */
  1581. ENTRY void
  1582. Fsconsist_FetchDirtyBlocks(consistPtr, invalidate)
  1583.     Fsconsist_Info *consistPtr;    /* Consistency state for file. */
  1584.     Boolean    invalidate;    /* If TRUE the client is told to invalidate
  1585.                  * after writing back the blocks */
  1586. {
  1587.     register    Fsconsist_ClientInfo    *clientPtr;
  1588.     register    Fsconsist_ClientInfo    *nextClientPtr;
  1589.  
  1590.     Fsutil_HandleUnlock(consistPtr->hdrPtr);
  1591.     LOCK_MONITOR;
  1592.  
  1593.     /*
  1594.      * Make sure that no one else is in the middle of performing cache
  1595.      * consistency on this handle.  If so wait until they are done.
  1596.      */
  1597.     while (consistPtr->flags & FS_CONSIST_IN_PROGRESS) {
  1598.     (void) Sync_Wait(&consistPtr->consistDone, FALSE);
  1599.     }
  1600.     /*
  1601.      * See if there are any dirty blocks to fetch.
  1602.      */
  1603.     if (consistPtr->lastWriter == -1 ||
  1604.     consistPtr->lastWriter == rpc_SpriteID) {
  1605.         UNLOCK_MONITOR;
  1606.     Fsutil_HandleLock(consistPtr->hdrPtr);
  1607.     return;
  1608.     }
  1609.     consistPtr->flags = FS_CONSIST_IN_PROGRESS;
  1610.  
  1611.     /*
  1612.      * There is a last writer.  In this case the only thing on the list is
  1613.      * the client that is the last writer because we know the domain for
  1614.      * the file is in-active.
  1615.      */
  1616.     nextClientPtr = (Fsconsist_ClientInfo *)List_First(&consistPtr->clientList);
  1617.     while (!List_IsAtEnd(&consistPtr->clientList, (List_Links *)nextClientPtr)){
  1618.     clientPtr = nextClientPtr;
  1619.     clientPtr->locked = FALSE;
  1620.     nextClientPtr = (Fsconsist_ClientInfo *)List_Next((List_Links *)clientPtr);
  1621.     if (!List_IsAtEnd(&consistPtr->clientList,(List_Links *)nextClientPtr)){
  1622.         nextClientPtr->locked = TRUE;
  1623.     }
  1624.     if (clientPtr->clientID != consistPtr->lastWriter) {
  1625.         Fsutil_HandleLock(consistPtr->hdrPtr);
  1626.         consistPtr->flags = 0;
  1627.         UNLOCK_MONITOR;
  1628.         panic("Fsconsist_FetchDirtyBlocks: Non last writer in list.\n");
  1629.         return;
  1630.     } else if (clientPtr->use.write > 0) {
  1631.         /*
  1632.          * The client has it actively open for writing.  In this case don't
  1633.          * do anything because he can have more dirty blocks anyway.
  1634.          */
  1635.     } else {
  1636.         register int flags = FSCONSIST_WRITE_BACK_BLOCKS;
  1637.         if (invalidate) {
  1638.         flags |= FSCONSIST_INVALIDATE_BLOCKS;
  1639.         }
  1640.         ClientCommand(consistPtr, clientPtr, flags);
  1641.         (void)EndConsistency(consistPtr);
  1642.     }
  1643.     }
  1644.     consistPtr->flags = 0;
  1645.     UNLOCK_MONITOR;
  1646.     Fsutil_HandleLock(consistPtr->hdrPtr);
  1647.     return;
  1648. }
  1649.  
  1650. /*
  1651.  * The consistency messages are issued in two parts.  In the first phase
  1652.  * the server issues all the clients commands, but the clients return
  1653.  * an RPC reply immediately and schedule ProcessConsist in the background
  1654.  * to actually effect the cache consistency.  The second phase consists
  1655.  * of the server waiting around for a return RPC by the client that
  1656.  * indicates that it is done.
  1657.  */
  1658. void    ProcessConsist();
  1659. void    ProcessConsistReply();
  1660. /*
  1661.  * Consist message information.
  1662.  */
  1663. typedef struct ConsistItem {
  1664.     int        serverID;
  1665.     ConsistMsg args;
  1666. } ConsistItem;
  1667.  
  1668. /*
  1669.  * ----------------------------------------------------------------------------
  1670.  *
  1671.  * ClientCommand --
  1672.  *
  1673.  *    Send an rpc to a client telling him to perform some cache 
  1674.  *    consistency operation.  Also put the client onto a list of 
  1675.  *    outstanding cache consistency messages.
  1676.  *
  1677.  * Results:
  1678.  *    The status from the RPC.
  1679.  *
  1680.  * Side effects:
  1681.  *    All locks except the consistency-in-progress lock are released
  1682.  *    during the call back to the client.  This allows operations like
  1683.  *    write-backs and unrelated closes of the file to complete.
  1684.  *    However, this means that the state of a file can change considerably
  1685.  *    during a call-back.  Of concern to routines in this file is that
  1686.  *    client list entries might get deleted, so LIST_FORALL doesn't work.
  1687.  *    Callers of ClientCommand have to be coded to reflect this.
  1688.  *
  1689.  * ----------------------------------------------------------------------------
  1690.  *
  1691.  */
  1692.  
  1693. INTERNAL void
  1694. ClientCommand(consistPtr, clientPtr, flags)
  1695.     register Fsconsist_Info *consistPtr;    /* Consistency state of file */
  1696.     Fsconsist_ClientInfo *clientPtr;    /* State of other client's cache */
  1697.     int            flags;        /* Command for the other client */
  1698. {
  1699.     Rpc_Storage        storage;
  1700.     ConsistMsg        consistRpc;
  1701.     ReturnStatus    status;
  1702.     ConsistMsgInfo    *msgPtr;
  1703.     int            numRefusals;
  1704.  
  1705.     if (clientPtr->clientID == rpc_SpriteID) {
  1706.     /*
  1707.      * Don't issue commands to ourselves (the server) because the commands
  1708.      * issued to the other clients (write-back, invalidate, etc.) will
  1709.      * all result in a consistent server cache anyway.
  1710.      */
  1711.     if (flags & FSCONSIST_INVALIDATE_BLOCKS) {
  1712.         /*
  1713.          * If we told ourselves to invalidate the file then mark us
  1714.          * as not caching the file.
  1715.          */
  1716.         clientPtr->cached = FALSE;
  1717.     }
  1718.     if (flags & FSCONSIST_WRITE_BACK_BLOCKS) {
  1719.         /*
  1720.          * We already have the most recent blocks.
  1721.          */
  1722.         consistPtr->lastWriter = -1;
  1723.     }
  1724.     if (clientPtr->use.ref == 0 && 
  1725.         consistPtr->lastWriter != clientPtr->clientID) {
  1726.         FSCACHE_DEBUG_PRINT1("ClientCommand: Removing %d ",
  1727.                     clientPtr->clientID);
  1728.         REMOVE_CLIENT(clientPtr);
  1729.     }
  1730.     return;
  1731.     }
  1732.     /*
  1733.      * Map to the client's view of the file (i.e. remote).
  1734.      */
  1735.     consistRpc.fileID = consistPtr->hdrPtr->fileID;
  1736.     if (consistRpc.fileID.type != FSIO_LCL_FILE_STREAM) {
  1737.         panic("ClientCommand, bad stream type <%d>\n",
  1738.             consistRpc.fileID.type);
  1739.     } else {
  1740.     consistRpc.fileID.type = FSIO_RMT_FILE_STREAM;
  1741.     }
  1742.     /*
  1743.      * The openTimeStamp lets the client catch races between this message
  1744.      * and the reply to an open it may be making at the same time.
  1745.      */
  1746.     consistRpc.flags = flags;
  1747.     consistRpc.openTimeStamp = clientPtr->openTimeStamp;
  1748.     consistRpc.version =
  1749.     ((Fsio_FileIOHandle *)consistPtr->hdrPtr)->cacheInfo.version;
  1750.  
  1751.     storage.requestParamPtr = (Address) &consistRpc;
  1752.     storage.requestParamSize = sizeof(ConsistMsg);
  1753.     storage.requestDataPtr = (Address) NIL;
  1754.     storage.requestDataSize = 0;
  1755.  
  1756.     storage.replyParamPtr = (Address) NIL;
  1757.     storage.replyParamSize = 0;
  1758.     storage.replyDataPtr = (Address) NIL;
  1759.     storage.replyDataSize = 0;
  1760.  
  1761.     /*
  1762.      * Put the client onto the list of outstanding cache consistency
  1763.      * messages.
  1764.      */
  1765.  
  1766.     msgPtr = (ConsistMsgInfo *) malloc(sizeof(ConsistMsgInfo));
  1767.     msgPtr->clientID = clientPtr->clientID;
  1768.     msgPtr->flags = consistRpc.flags;
  1769.     List_Insert((List_Links *) msgPtr, LIST_ATREAR(&consistPtr->msgList));
  1770.  
  1771.     /*
  1772.      * Have to release this monitor during the call-back so that
  1773.      * an unrelated close can complete its call to Fsconsist_Close.
  1774.      * Alternatives are to fix the consistency call-back RPC stubs
  1775.      * so they don't lock the handle.
  1776.      */
  1777.     if ((consistPtr->flags & FS_CONSIST_IN_PROGRESS) == 0) {
  1778.     panic( "Client CallBack - consist flag not set\n");
  1779.     }
  1780.     UNLOCK_MONITOR;
  1781.     numRefusals = 0;
  1782.     while ( TRUE ) {
  1783.     /*
  1784.      * Send the rpc to the client.  The client will return FAILURE if the
  1785.      * open that we are talking about hasn't returned to the client yet.
  1786.      */
  1787.     status = Rpc_Call(clientPtr->clientID, RPC_FS_CONSIST, &storage);
  1788.     if (status != FAILURE) {
  1789.         break;
  1790.     } else {
  1791.         numRefusals++;
  1792.         if (numRefusals > 30) {
  1793.         printf("Client %d dropped 30 %s requests for \"%s\" <%d,%d>\n",
  1794.                 clientPtr->clientID, ConsistType(flags),
  1795.                 Fsutil_HandleName(consistPtr->hdrPtr),
  1796.                 consistRpc.fileID.major, consistRpc.fileID.minor);
  1797.         numRefusals = 0;
  1798.         }
  1799.     }
  1800.     }
  1801.     if (status != SUCCESS) {
  1802.     /*
  1803.      * Couldn't post call-back to the client.
  1804.      */
  1805.     int ref, write, exec;
  1806.     int clientID = clientPtr->clientID;
  1807.     printf("ClientCommand, %s msg to client %d file \"%s\" <%d,%d> failed %x\n",
  1808.         ConsistType(flags), clientID, Fsutil_HandleName(consistPtr->hdrPtr),
  1809.         consistRpc.fileID.major, consistRpc.fileID.minor, status);
  1810.     if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE) {
  1811.         /*
  1812.          * If its really down, then nuke it from the
  1813.          * list of clients using the file.
  1814.          */
  1815.         Fsconsist_Kill(consistPtr, clientPtr->clientID, &ref, &write, &exec);
  1816.         printf("\tClient state killed: %d refs %d write %d exec\n",
  1817.             ref, write, exec);
  1818.     } else {
  1819.         /*
  1820.          * Just nuke the message from the list so EndConsistency
  1821.          * terminates.  Sometimes the callback fails because the
  1822.          * host is still booting and hasn't enabled its RPC service yet.
  1823.          */
  1824.         List_Remove((List_Links *)msgPtr);
  1825.         free((Address)msgPtr);
  1826.     }
  1827.     }
  1828.     LOCK_MONITOR;
  1829. }
  1830.  
  1831. /*
  1832.  *----------------------------------------------------------------------
  1833.  *
  1834.  * Fsconsist_RpcConsist --
  1835.  *
  1836.  *    Service stub for RPC_FS_CONSIST.  This is executed on a filesystem
  1837.  *    client in response to a cache consistency command.  This schedules
  1838.  *    a call to ProcessConsist and returns a reply to the server.
  1839.  *    If, by remote chance, the message concerns an in-progress open
  1840.  *    that hasn't yet completed, we just return an error code to the
  1841.  *    server so that it will re-send its request after we know about
  1842.  *    the open.
  1843.  *
  1844.  * Results:
  1845.  *    SUCCESS.
  1846.  *
  1847.  * Side effects:
  1848.  *    Add work to the queue for the client consistency process.
  1849.  *
  1850.  *----------------------------------------------------------------------
  1851.  */
  1852. /*ARGSUSED*/
  1853. ReturnStatus
  1854. Fsconsist_RpcConsist(srvToken, clientID, command, storagePtr)
  1855.     ClientData srvToken;    /* Handle on server process passed to
  1856.                  * Rpc_Reply */
  1857.     int clientID;        /* ID of server controlling the file */
  1858.     int command;        /* Command identifier */
  1859.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  1860.                  * buffers and also indicate the exact amount
  1861.                  * of data in the request buffers.  The reply
  1862.                  * fields are initialized to NIL for the
  1863.                  * pointers and 0 for the lengths.  This can
  1864.                  * be passed to Rpc_Reply */
  1865. {
  1866.     register ConsistMsg        *consistArgPtr;
  1867.     register ConsistItem    *consistPtr;
  1868.     register Fsrmt_FileIOHandle    *rmtHandlePtr;
  1869.     register ReturnStatus    status;
  1870.  
  1871.     consistArgPtr = (ConsistMsg *)storagePtr->requestParamPtr;
  1872.     if (consistArgPtr->fileID.type != FSIO_RMT_FILE_STREAM) {
  1873.     printf("Fsconsist_RpcConsist bad fileID <%d,%d,%d,%d> from client %d\n",
  1874.             consistArgPtr->fileID.type, consistArgPtr->fileID.serverID,
  1875.             consistArgPtr->fileID.major, consistArgPtr->fileID.minor,
  1876.             clientID);
  1877.     return(FAILURE);
  1878.     }
  1879.     /*
  1880.      * This fetch locks the handle.  In earlier versions of the kernel
  1881.      * this could cause deadlock.  This may still be true.  3/9/88.
  1882.      */
  1883.     rmtHandlePtr = Fsutil_HandleFetchType(Fsrmt_FileIOHandle,
  1884.                       &consistArgPtr->fileID);
  1885.     if (rmtHandlePtr == (Fsrmt_FileIOHandle *)NIL) {
  1886.     if (Fsprefix_OpenInProgress(&consistArgPtr->fileID) == 0) {
  1887.         status = FS_STALE_HANDLE;
  1888.     } else {
  1889.         /*
  1890.          * A consistency message has arrived from an open from which
  1891.          * we haven't received the reply.  Return FAILURE to force
  1892.          * the server to resend and give the open reply a chance
  1893.          * of getting to us.  This is the "open/consistency race".
  1894.          */
  1895.         status = FAILURE;
  1896.     }
  1897.     } else if (rmtHandlePtr->openTimeStamp != consistArgPtr->openTimeStamp) {
  1898.     if ((rmtHandlePtr->cacheInfo.version == consistArgPtr->version) &&
  1899.         ((consistArgPtr->flags & (FSCONSIST_DELETE_FILE|
  1900.                      FSCONSIST_WRITE_BACK_BLOCKS)) == 0)) {
  1901.         /*
  1902.          * We have the same version as the server, but there has been
  1903.          * more open traffic than we realize.  If this is any command
  1904.          * except a write-back or delete (like return-attrs), then
  1905.          * we'll do it.
  1906.          */
  1907.         status = SUCCESS;
  1908.     } else if (Fsprefix_OpenInProgress(&consistArgPtr->fileID) == 0) {
  1909.         status = FS_STALE_HANDLE;
  1910.         printf("Fsconsist_RpcConsist: <%d,%d> %s msg from %d timestamp %d not %d\n\t version %d and %d, returning stale handle\n",
  1911.             consistArgPtr->fileID.major,
  1912.             consistArgPtr->fileID.minor,
  1913.             ConsistType(consistArgPtr->flags),
  1914.             consistArgPtr->fileID.serverID,
  1915.             consistArgPtr->openTimeStamp, rmtHandlePtr->openTimeStamp,
  1916.             consistArgPtr->version, rmtHandlePtr->cacheInfo.version);
  1917.     } else {
  1918.         /*
  1919.          * Timestamp mis-match and an open in progress.
  1920.          * Possible open/consistency race.
  1921.          */
  1922.         status = FAILURE;
  1923.     }
  1924.     } else {
  1925.     status = SUCCESS;
  1926.     }
  1927.  
  1928.     if (rmtHandlePtr != (Fsrmt_FileIOHandle *)NIL) {
  1929.     Fsutil_HandleRelease(rmtHandlePtr, TRUE);
  1930.     }
  1931.     if (status == SUCCESS) {
  1932.     /*
  1933.      * This is a message corresponding to our current notion of the
  1934.      * file.  Pass the message to a consistency handler process.
  1935.      */
  1936.     consistPtr = (ConsistItem *) malloc(sizeof(ConsistItem));
  1937.     consistPtr->serverID = clientID;
  1938.     consistPtr->args = *consistArgPtr;
  1939.     Proc_CallFunc(ProcessConsist, (ClientData) consistPtr, 0);
  1940.     }
  1941.     Rpc_Reply(srvToken, status, storagePtr, (int(*)())NIL, (ClientData)NIL);
  1942.     return(SUCCESS);
  1943. }
  1944.  
  1945.  
  1946. /*
  1947.  * ----------------------------------------------------------------------------
  1948.  *
  1949.  * ProcessConsist --
  1950.  *
  1951.  *    Process a cache consistency request from the server.  This
  1952.  *    is called in the background as the result of a request from
  1953.  *    the server.  This routine is a thin wrapper around a routine
  1954.  *    in the cache module that does all the work.
  1955.  *
  1956.  * Results:
  1957.  *    None.
  1958.  *
  1959.  * Side effects:
  1960.  *    See Fscache_Consist.
  1961.  *
  1962.  * ----------------------------------------------------------------------------
  1963.  *
  1964.  */
  1965. void
  1966. ProcessConsist(data, callInfoPtr)
  1967.     ClientData        data;
  1968.     Proc_CallInfo    *callInfoPtr;
  1969. {
  1970.     register Fsrmt_FileIOHandle     *handlePtr;
  1971.     ReturnStatus        status;
  1972.     Rpc_Storage            storage;
  1973.     ConsistReply        reply;
  1974.     register    ConsistItem    *consistPtr;
  1975.  
  1976.     consistPtr = (ConsistItem *) data;
  1977.     callInfoPtr->interval = 0;
  1978.  
  1979.     handlePtr = Fsutil_HandleFetchType(Fsrmt_FileIOHandle,
  1980.                        &consistPtr->args.fileID);
  1981.     if (handlePtr == (Fsrmt_FileIOHandle *)NIL) {
  1982.     printf("ProcessConsist: no handle <%d, %d, %d, %d>\n",
  1983.             consistPtr->args.fileID.type,
  1984.             consistPtr->args.fileID.serverID,
  1985.             consistPtr->args.fileID.major,
  1986.             consistPtr->args.fileID.minor);
  1987.     free((char *) consistPtr);
  1988.     return;
  1989.     }
  1990.     Fsutil_HandleUnlock(handlePtr);
  1991.  
  1992.     FSCACHE_DEBUG_PRINT2("ProcessConsist: Got %s request for file %d\n", 
  1993.     ConsistType(consistPtr->args.flags), handlePtr->rmt.hdr.fileID.minor);
  1994.  
  1995.     /*
  1996.      * Process the request under the per file cache lock.
  1997.      */
  1998.     reply.status = Fscache_Consist(&handlePtr->cacheInfo,
  1999.             consistPtr->args.flags, &reply.cachedAttr);
  2000.     reply.fileID = handlePtr->rmt.hdr.fileID;
  2001.     reply.fileID.type = FSIO_LCL_FILE_STREAM;
  2002.     Fsutil_HandleRelease(handlePtr, FALSE);
  2003.     /*
  2004.      * Set up the reply buffer.
  2005.      */
  2006.     storage.requestParamPtr = (Address)&reply;
  2007.     storage.requestParamSize = sizeof(ConsistReply);
  2008.     storage.requestDataPtr = (Address)NIL;
  2009.     storage.requestDataSize = 0;
  2010.     storage.replyParamPtr = (Address)NIL;
  2011.     storage.replyParamSize = 0;
  2012.     storage.replyDataPtr = (Address)NIL;
  2013.     storage.replyDataSize = 0;
  2014.  
  2015.     for ( ; ; ) {
  2016.     status = Rpc_Call(consistPtr->serverID, RPC_FS_CONSIST_REPLY, &storage);
  2017.     if (status != SUCCESS) {
  2018.         printf("Got error (%x) from consist reply on <%d,%d>\n", status,
  2019.         reply.fileID.major, reply.fileID.minor);
  2020.     }
  2021.     if (status != RPC_TIMEOUT) {
  2022.         break;
  2023.     }
  2024.     }
  2025.     free((Address)consistPtr);
  2026. }
  2027.  
  2028.  
  2029. /*
  2030.  *----------------------------------------------------------------------
  2031.  *
  2032.  * Fsconsist_RpcConsistReply --
  2033.  *
  2034.  *    Service stub for RPC_FS_CONSIST_REPLY.  This RPC indicates that
  2035.  *    the client has completed the consistency actions we previously
  2036.  *    asked it to perform.
  2037.  *
  2038.  * Results:
  2039.  *    SUCCESS, unless we don't like the fileID specified by the client.
  2040.  *
  2041.  * Side effects:
  2042.  *    See ProcessConsistReply.
  2043.  *
  2044.  *----------------------------------------------------------------------
  2045.  */
  2046. /*ARGSUSED*/
  2047. ReturnStatus
  2048. Fsconsist_RpcConsistReply(srvToken, clientID, command, storagePtr)
  2049.     ClientData srvToken;    /* Handle on server process passed to
  2050.                  * Rpc_Reply */
  2051.     int clientID;        /* Sprite ID of client host */
  2052.     int command;        /* Command identifier */
  2053.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  2054.                  * buffers and also indicate the exact amount
  2055.                  * of data in the request buffers.  The reply
  2056.                  * fields are initialized to NIL for the
  2057.                  * pointers and 0 for the lengths.  This can
  2058.                  * be passed to Rpc_Reply */
  2059. {
  2060.     Fsio_FileIOHandle    *handlePtr;
  2061.     ConsistReply    *replyPtr;
  2062.  
  2063.     replyPtr = (ConsistReply *) storagePtr->requestParamPtr;
  2064.     if (replyPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  2065.     printf("Fsconsist_RpcConsistReply: bad fileID <%d,%d,%d,%d> from client %d\n",
  2066.         replyPtr->fileID.type, replyPtr->fileID.serverID,
  2067.         replyPtr->fileID.major, replyPtr->fileID.minor, clientID);
  2068.         return(GEN_INVALID_ARG);
  2069.     }
  2070.     handlePtr = Fsutil_HandleFetchType(Fsio_FileIOHandle, &(replyPtr->fileID));
  2071.     if (handlePtr == (Fsio_FileIOHandle *) NIL) {
  2072.     printf("Fsconsist_RpcConsistReply: no handle <%d,%d> for client %d\n",
  2073.         replyPtr->fileID.major, replyPtr->fileID.minor, clientID);
  2074.     return(FS_STALE_HANDLE);
  2075.     }
  2076.     /*
  2077.      * Unlock the handle to prevent deadlock if this RPC
  2078.      * arrives as ClientRemoveCallback is attempting to relock
  2079.      * the handle on its way out of the per-file consistency monitor.
  2080.      * (This can only happen if the server 'kills' the client state and so
  2081.      * aborts the cache consistency wait before this arrives.)
  2082.      * Ordinarily this RPC arrives as it is waiting with the monitor
  2083.      * unlocked.  The handle lock is not needed anyway because once we have
  2084.      * successfully fetched the handle it won't go away on us.  Furthermore,
  2085.      * ProcessConsistReply can handle it if the client state has been killed.
  2086.      */
  2087.     Fsutil_HandleUnlock(handlePtr);
  2088.     ProcessConsistReply(&handlePtr->consist, clientID, replyPtr);
  2089.     Fsutil_HandleRelease(handlePtr, FALSE);
  2090.     Rpc_Reply(srvToken, SUCCESS, storagePtr, 
  2091.           (int (*)())NIL, (ClientData)NIL);
  2092.     return(SUCCESS);
  2093. }
  2094.  
  2095.  
  2096. /*
  2097.  *----------------------------------------------------------------------
  2098.  *
  2099.  * ProcessConsistReply --
  2100.  *
  2101.  *    Process the reply sent by the client for the given handle.
  2102.  *    This updates the caching state of the client, and it may
  2103.  *    also update the handle attributes based on information returned
  2104.  *    from the client.  This is call after the client has completed
  2105.  *    the cache consistency actions we previously requested of it.
  2106.  *
  2107.  * Results:
  2108.  *    None.
  2109.  *
  2110.  * Side effects:
  2111.  *    Element deleted from the list of outstanding client consist 
  2112.  *    messages.  Also if the message was for invalidation then the
  2113.  *    client list entry is marked as non-cacheable.  IMPORTANT:
  2114.  *    client list entry may be REMOVED here which prevents safe
  2115.  *    use of LIST_FORALL iteration over the client list by any
  2116.  *    routine that calls ClientCommand (which eventually gets us called)
  2117.  *
  2118.  *----------------------------------------------------------------------
  2119.  */
  2120. ENTRY void
  2121. ProcessConsistReply(consistPtr, clientID, replyPtr)
  2122.     Fsconsist_Info        *consistPtr;    /* File to process reply for*/
  2123.     int                clientID;    /* Client who sent us the 
  2124.                          * reply. */
  2125.     register    ConsistReply    *replyPtr;    /* The reply that was sent. */
  2126. {
  2127.     register    ConsistMsgInfo        *msgPtr;
  2128.     register    Fsconsist_ClientInfo     *clientPtr;
  2129.     Boolean                found = FALSE;
  2130.     Fsio_FileIOHandle            *handlePtr;
  2131.  
  2132.     LOCK_MONITOR;
  2133.  
  2134.     /*
  2135.      * Find the client in the list of pending messages.  Notify the
  2136.      * opening process after all the clients have responded.
  2137.      */
  2138.     LIST_FORALL(&(consistPtr->msgList), (List_Links *) msgPtr) {
  2139.     if (msgPtr->clientID == clientID) {
  2140.         List_Remove((List_Links *) msgPtr);
  2141.         found = TRUE;
  2142.         break;
  2143.     }
  2144.     }
  2145.     if (List_IsEmpty(&(consistPtr->msgList))) {
  2146.     Sync_Broadcast(&consistPtr->repliesIn);
  2147.     }
  2148.     if (!found) {
  2149.     /*
  2150.      * We don't know about this cache consistency action by the
  2151.      * client, perhaps because we concluded it was down and
  2152.      * killed our state about it.  It is also possible that it is an
  2153.      * old message from the client, probably queued in the network
  2154.      * interface across a reboot or from a gateway.
  2155.      */
  2156.     UNLOCK_MONITOR;
  2157.     return;
  2158.     }
  2159.     if (replyPtr->status != SUCCESS) {
  2160.     printf("ProcessConsist: %s request failed <%x> file \"%s\" <%d,%d>\n",
  2161.         ConsistType(msgPtr->flags), replyPtr->status,
  2162.         Fsutil_HandleName(consistPtr->hdrPtr),
  2163.         consistPtr->hdrPtr->fileID.major,
  2164.         consistPtr->hdrPtr->fileID.minor);
  2165.     consistPtr->flags |= FS_CONSIST_ERROR;
  2166.     } else {
  2167.     if ((msgPtr->flags & FSCONSIST_WRITE_BACK_BLOCKS) &&
  2168.         (consistPtr->lastWriter == clientID)) {
  2169.         /*
  2170.          * We just got the most recent blocks so we don't care who the
  2171.          * last writer is anymore.
  2172.          */
  2173.         consistPtr->lastWriter = -1;
  2174.     }
  2175.     /*
  2176.      * Look for client list entry that match the client, and update
  2177.      * its state to reflect the consistency action by the client.
  2178.      * Because we've release the monitor lock during the previous
  2179.      * call-back, an unrelated action may have removed the client
  2180.      * from the list - no big deal.
  2181.      */
  2182.     LIST_FORALL(&(consistPtr->clientList), (List_Links *) clientPtr) {
  2183.         if (clientPtr->clientID == clientID) {
  2184.         Fsrecov_HandleState    recovInfo;
  2185.         ReturnStatus    status;
  2186.  
  2187.         handlePtr = (Fsio_FileIOHandle *)consistPtr->hdrPtr;
  2188.         if (msgPtr->flags & (FSCONSIST_WRITE_BACK_BLOCKS |
  2189.                      FSCONSIST_WRITE_BACK_ATTRS)) {
  2190.             Fscache_UpdateAttrFromClient(clientID,
  2191.                 &handlePtr->cacheInfo, &replyPtr->cachedAttr);
  2192.             (void) Fsdm_UpdateDescAttr(handlePtr, 
  2193.                     &handlePtr->cacheInfo.attr, -1);
  2194.         }
  2195.         if (clientPtr->use.ref == 0 &&
  2196.             consistPtr->lastWriter != clientID) {
  2197.  
  2198.             /*
  2199.              * If the handle had a 0 ref count but was still in the
  2200.              * recovery box due to having dirty blocks in the client's
  2201.              * cache, we can now get rid of it.  XXX I hope this is
  2202.              * the right place to do it.  Should it be done
  2203.              * above?  Leaving it here could get more clients,
  2204.              * but if they aren't the last writer and they have 0 refs,
  2205.              * they should go away.
  2206.              */
  2207.             if (recov_Transparent &&
  2208.                 Fsrecov_GetHandle(consistPtr->hdrPtr->fileID,
  2209.                 clientID, &recovInfo, FALSE) == SUCCESS) {
  2210.             if (recovInfo.use.ref <= 0) {
  2211.                 status = Fsrecov_DeleteHandle(consistPtr->hdrPtr,
  2212.                     clientID, FS_WRITE | FS_LAST_DIRTY_BLOCK);
  2213.                 if (status != SUCCESS) {
  2214.                 /* Should I panic? */
  2215.                 printf("ProcessConsistReply: couldn't ");
  2216.                 printf("delete handle from recov box.\n");
  2217.                 }
  2218.             } else {
  2219.                 printf("ProcessConsistReply: ref count ");
  2220.                 panic("on object too high.");
  2221.             }
  2222.             }
  2223.             REMOVE_CLIENT(clientPtr);
  2224.         } else if (msgPtr->flags & FSCONSIST_INVALIDATE_BLOCKS) {
  2225.             clientPtr->cached = FALSE;
  2226.             /* Change cacheability info in recov box. */
  2227.             if (recov_Transparent &&
  2228.                 Fsrecov_GetHandle(consistPtr->hdrPtr->fileID,
  2229.                 clientID, &recovInfo, FALSE) == SUCCESS) {
  2230.             if (recovInfo.clientData != FALSE) {
  2231.                 recovInfo.clientData = FALSE;
  2232.                 if (Fsrecov_UpdateHandle(consistPtr->hdrPtr->fileID,
  2233.                     clientID, &recovInfo) != SUCCESS) {
  2234.                 printf(" ProcessConsistReply: ");
  2235.                 printf("Couldn't update recov box.\n");
  2236.                 }
  2237.             }
  2238.             }
  2239.         }
  2240.         break;
  2241.         }
  2242.     }
  2243.     }
  2244.     free((Address) msgPtr);
  2245.  
  2246.     UNLOCK_MONITOR;
  2247. }
  2248.  
  2249.  
  2250. /*
  2251.  *----------------------------------------------------------------------
  2252.  *
  2253.  * ConsistType --
  2254.  *
  2255.  *    Utility routine to map from consistency flags to a printable string.
  2256.  *
  2257.  * Results:
  2258.  *    A pointer to a printable string.
  2259.  *
  2260.  * Side effects:
  2261.  *    None.
  2262.  *
  2263.  *----------------------------------------------------------------------
  2264.  */
  2265.  
  2266. char *
  2267. ConsistType(flags)
  2268.     int flags;        /* Cache consistency message flags */
  2269. {
  2270.     register char *result;
  2271.  
  2272.     switch (flags) {
  2273.     case FSCONSIST_WRITE_BACK_BLOCKS:
  2274.     result = "write-back";
  2275.     break;
  2276.     case FSCONSIST_INVALIDATE_BLOCKS:
  2277.     result = "invalidate";
  2278.     break;
  2279.     case (FSCONSIST_WRITE_BACK_BLOCKS|FSCONSIST_INVALIDATE_BLOCKS):
  2280.     result = "write-back & invalidate";
  2281.     break;
  2282.     case FSCONSIST_DELETE_FILE:
  2283.     result = "delete";
  2284.     break;
  2285.     case FSCONSIST_WRITE_BACK_ATTRS:
  2286.     result = "return-attrs";
  2287.     break;
  2288.     default:
  2289.     result = "UNKNOWN";
  2290.     break;
  2291.     }
  2292.     return result;
  2293. }
  2294.  
  2295. /*
  2296.  * ----------------------------------------------------------------------------
  2297.  *
  2298.  * Fsconsist_UpdateFileConsistencyList --
  2299.  *
  2300.  *    This updates the data structures to include this file in the
  2301.  *    client consistency lists.
  2302.  *
  2303.  * Results:
  2304.  *    None.
  2305.  *
  2306.  * Side effects:
  2307.  *    Lists updated, lastWriter field set, etc.
  2308.  *
  2309.  * ----------------------------------------------------------------------------
  2310.  *
  2311.  */
  2312. ENTRY void
  2313. Fsconsist_UpdateFileConsistencyList(handlePtr, clientID, useFlags, cacheable)
  2314.     Fsio_FileIOHandle *handlePtr;    /* File to check consistency of. */
  2315.     int         clientID;    /* ID of the host doing the open */
  2316.     register int     useFlags;    /* useFlags from the open call */
  2317.     Boolean        cacheable;    /* TRUE if file is cacheable. */
  2318. {
  2319.     register Fsconsist_Info *consistPtr = &handlePtr->consist;
  2320.     LOCK_MONITOR;
  2321.  
  2322.     /*
  2323.      * Add ourselves to the list of clients using the file.
  2324.      */
  2325.     UpdateList(consistPtr, clientID, useFlags, cacheable, (int *) NIL);
  2326.     UNLOCK_MONITOR;
  2327.     return;
  2328. }
  2329.